package com.omega.encryptedsql.handler;


import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.omega.encryptedsql.configuration.EntityCapturePlugin;
import com.omega.encryptedsql.manager.EncryptorManager;
import com.omega.encryptedsql.properties.EncryptProperties;
import com.omega.encryptedsql.registry.EntityFieldRegistry;
import com.omega.encryptedsql.utils.EntityClassExtractor;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;

@Component
public class SmartEncryptTypeHandler extends BaseTypeHandler<String> {

    private final EncryptorManager encryptorManager;
    private final EncryptProperties encryptProperties;
    private final EntityFieldRegistry fieldRegistry;

    @Autowired
    public SmartEncryptTypeHandler(EncryptorManager encryptorManager,
                                   EncryptProperties encryptProperties,
                                   EntityFieldRegistry fieldRegistry) {
        this.encryptorManager = encryptorManager;
        this.encryptProperties = encryptProperties;
        this.fieldRegistry = fieldRegistry;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i,
                                    String parameter, JdbcType jdbcType) throws SQLException {
        try {
           Object entity = EntityCapturePlugin.getCurrentEntity();
            if (entity != null) {
                Class<?> entityClass = null;
                if (entity instanceof Map) {
                    Map<?, ?> paramMap = (Map<?, ?>) entity;
                    entityClass = EntityClassExtractor.extractFromParameterObject(paramMap);
                } else {
                    entityClass = entity.getClass();
                }
                TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
                // 尝试获取字段名（通过参数位置）
                String fieldName = getFieldNameForParameter(ps, i, tableInfo);

                if (fieldName != null) {
                    EntityFieldRegistry.FieldMeta fieldMeta = fieldRegistry.getFieldMeta(
                            entityClass, fieldName);

                    if (shouldEncrypt(fieldMeta, parameter)) {
                        String encrypted = encryptorManager.encrypt(
                                parameter, fieldMeta.getKeyId());
                        ps.setString(i, encrypted);
                        return;
                    }
                }
            }
            // 默认处理
            ps.setString(i, parameter);
        } catch (Exception e) {
            throw new SQLException("Encryption processing failed", e);
        }


    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String value = rs.getString(columnName);
        return decryptValue(value, rs, columnName);
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String value = rs.getString(columnIndex);
        return decryptValue(value, rs, rs.getMetaData().getColumnName(columnIndex));
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String value = cs.getString(columnIndex);
        return decryptValue(value, cs, cs.getMetaData().getColumnName(columnIndex));
    }

    private String decryptValue(String value, Object source, String columnName) {
        if (value == null || value.isEmpty() || !encryptProperties.isEnabled()) {
            return value;
        }

        try {
            // 获取结果集对应的实体类
            Class<?> entityClass = inferEntityClassFromSource(source);

            if (entityClass != null) {
                // 通过列名查找字段元数据
                EntityFieldRegistry.FieldMeta fieldMeta = findFieldMetaByColumn(entityClass, columnName);

                if (shouldDecrypt(fieldMeta, value)) {
                    return encryptorManager.decrypt(value);
                }
            } else if (encryptorManager.isLikelyEncrypted(value)) {
                // 无法确定实体类，但值看起来是加密的
                return encryptorManager.decrypt(value);
            }

            return value;
        } catch (Exception e) {
            throw new RuntimeException("Decryption processing failed", e);
        }
    }

    private Class<?> inferEntityClassFromSource(Object source) {
        // 在实际应用中，可以通过解析SQL或上下文推断实体类
        // 这里简化处理，返回null
        return null;
    }

    private EntityFieldRegistry.FieldMeta findFieldMetaByColumn(Class<?> entityClass, String columnName) {
        Map<String, EntityFieldRegistry.FieldMeta> fieldMap = fieldRegistry.getFieldCache().get(entityClass);
        if (fieldMap != null) {
            for (EntityFieldRegistry.FieldMeta fieldMeta : fieldMap.values()) {
                if (fieldMeta.getColumnName().equalsIgnoreCase(columnName)) {
                    return fieldMeta;
                }
            }
        }
        return null;
    }

    private String getFieldNameForParameter(PreparedStatement ps, int paramIndex, TableInfo tableInfo) {
        // 简化处理 - 实际应用中需要更复杂的逻辑
        if (tableInfo != null && paramIndex <= tableInfo.getFieldList().size()) {
            return tableInfo.getFieldList().get(paramIndex - 1).getField().getName();
        }
        return null;
    }

    private boolean shouldEncrypt(EntityFieldRegistry.FieldMeta fieldMeta, String value) {
        if (fieldMeta == null) return false;
        return fieldMeta.isSensitive() && value != null && !value.isEmpty();
    }

    private boolean shouldDecrypt(EntityFieldRegistry.FieldMeta fieldMeta, String value) {
        if (fieldMeta == null) return encryptorManager.isLikelyEncrypted(value);
        return fieldMeta.isSensitive();
    }

}
